#pragma once
#include <string>
#include <cstdlib>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <unistd.h>
#include "log.hpp"
namespace Server
{
    enum err
    {
        USAGE_ERR = 1,
        SOCKET_ERR,
        BIND_ERR,
        OPEN_ERR,
        LISTEN_ERR,
    }Err;
    const static uint16_t gport = 8888;// 缺省端口号  云服务器需要开放端口号
    const static int gbacklog = 5;// 最大连接数 5 + 1
    const static std::string defaultIp = "0.0.0.0";
    class TcpServer
    {
    public:
        TcpServer(const uint16_t& port = gport, const std::string& ip = defaultIp)
            :_listenSocket(-1)
            ,_port(port)
            ,_ip(ip)
        {}
        void InitServer()// 初始化
        {
            // 1.创建socket套接字
            _listenSocket = socket(AF_INET, SOCK_STREAM, 0);// 字节流
            if (_listenSocket < 0) 
            {
                LogMessage(SOCKET_ERR, "create socket error");
                exit(SOCKET_ERR);
            }
            // 2. 绑定ip和端口号
            struct sockaddr_in local; // #include <arpa/inet.h>
            // 转ip和端口号，设置协议族
            local.sin_addr.s_addr = inet_addr(_ip.c_str());
            local.sin_family = AF_INET;
            local.sin_port = htons(_port);

            int n = bind(_listenSocket, (struct sockaddr*)&local, sizeof(local));
            if (n < 0) 
            {
                LogMessage(BIND_ERR, "bind error");
                exit(BIND_ERR);
            }
            // 3. 设置监听状态
            n = listen(_listenSocket, gbacklog);// backlog监听队列的最大连接数量
            if (n < 0)
            {
                LogMessage(FATAL, "listen error");
                exit(LISTEN_ERR);
            }
            LogMessage(NORMAL, "listen socket success");
        }
        void Start()// 启动
        {
            // 4. 服务器获取客户端连接请求
            while (1)
            {
                struct sockaddr_in peer;// 输出型参数，获得客户端信息
                peer.sin_family = AF_INET;
                peer.sin_addr.s_addr = inet_addr(_ip.c_str());
                peer.sin_port = htons(_port);
                socklen_t len = sizeof(peer);
                int socket = accept(_listenSocket, (struct sockaddr*)&peer, &len);
                if (socket < 0)
                {
                    LogMessage(ERROR, "accept erro, next");
                    continue;
                }
                LogMessage(NORMAL, "accept a new link success");
                // 5. 使用accept返回的socket通信，均为文件操作
                ServerIO(socket);
                close(socket);// 使用完关闭，避免资源泄露
            }
        }
        void ServerIO(int socket)
        {
            char buffer[1024];
            while (1)
            {
                // 服务器读取客户端数据，通过套接字sock这个文件描述符读取数据
                ssize_t n = read(socket, buffer, sizeof(buffer) - 1);
                if (n > 0)
                {
                    buffer[n] = 0;
                    std::cout << "recv message:" << buffer << std::endl;
                    std::string outBuffer = buffer;
                    outBuffer += "[server echo]";
                    // 服务器将数据处理后发送回客户端
                    write(socket, outBuffer.c_str(), outBuffer.size());
                }
                else if (0 == n) // 服务器read返回值为0，说明客户端关闭了
                {
                    LogMessage(NORMAL, "client quit,server quit");
                    break;// 退出只是断开了和客户端的连接，服务器没有关闭
                }
            }           
        }                                                                                                
        ~TcpServer()
        {

        }
        private:
            int _listenSocket; // 监听客户端连接请求，不用于数据通信
            uint16_t _port;    // 服务器端口号
            std::string _ip;   // 服务器ip
        };
}